package com.ruoyi.app.service.impl;

import com.ruoyi.app.mapper.AppMapper;
import com.ruoyi.app.service.ICallbackService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.domain.*;
import com.ruoyi.framework.config.SmartParkingCloudConfig;
import com.ruoyi.mapper.*;
import com.ruoyi.wss.WebSocketMessageService;
import com.ruoyi.wss.dahua.Enum.MasWebsocketEnum;
import com.ruoyi.wss.dahua.config.DaHuaConfig;
import com.ruoyi.wss.dahua.request.*;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 回调Service业务层处理
 * 
 * @author dongdong
 * @date 2025-08-20
 */
@Slf4j
@Service
public class CallbackServiceImpl implements ICallbackService {

    @Autowired
    private NotificationParser notificationParser;
    @Autowired
    private RefundService refundService;
    @Autowired
    private WebSocketMessageService webSocketMessageService;
    @Resource
    private ParkingOrderMapper parkingOrderMapper;
    @Resource
    private ParkingCardOrderMapper parkingCardOrderMapper;
    @Resource
    private ParkingCardMapper parkingCardMapper;
    @Resource
    private ParkingInfoMapper parkingInfoMapper;
    @Resource
    private ParkingCardRefundMapper parkingCardRefundMapper;

    @Override
    public Map<String, String> wechatPayNotify(Map<String, String> headers, String body) {
        // 需要先验证签名、解密通知中的密文信息
        Map<String, String> response = new HashMap<>();
        try {
            // 1. 构造请求对象，提取微信headers
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(headers.get("wechatpay-serial"))
                    .nonce(headers.get("wechatpay-nonce"))
                    .timestamp(headers.get("wechatpay-timestamp"))
                    .signature(headers.get("wechatpay-signature"))
                    .body(body)
                    .build();

            // 2. 验签 + 解密
            Transaction transaction = notificationParser.parse(requestParam, Transaction.class);
            // 3. 拿到明文
            String tradeState = transaction.getTradeState().toString();
            log.info("微信支付通知: 订单号={}, 内容={}", transaction.getOutTradeNo(), transaction);
            switch (tradeState) {
                case "SUCCESS": // 支付成功
                    wechatPaymentSuccess(transaction);
                    break;

                case "CLOSED": // 订单关闭
                    wechatOrderClosed(transaction);
                    break;

                case "PAYERROR": // 支付错误
                    wechatPaymentError(transaction);
                    break;

                default:
                    log.error("未知的交易状态: {}", tradeState);
            }
            // 4. 返回成功响应（微信要求必须返回 SUCCESS，否则会反复重试）
            response.put("code", "SUCCESS");
            response.put("message", "处理成功");
        } catch (Exception e) {
            e.printStackTrace();
            response.put("code", "FAIL");
            response.put("message", "处理失败: " + e.getMessage());
        }
        return response;
    }

    @Override
    public Map<String, String> refundNotify(Map<String, String> headers, String body) {
        // 需要先验证签名、解密通知中的密文信息
        Map<String, String> response = new HashMap<>();
        try {
            // 1. 构造请求对象，提取微信headers
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(headers.get("wechatpay-serial"))
                    .nonce(headers.get("wechatpay-nonce"))
                    .timestamp(headers.get("wechatpay-timestamp"))
                    .signature(headers.get("wechatpay-signature"))
                    .body(body)
                    .build();

            // 2. 验签 + 解密
            RefundNotification notification = notificationParser.parse(requestParam, RefundNotification.class);
            log.info("微信退款回调: 退款单号={}, 内容={}", notification.getOutRefundNo(), notification);
            // 3. 拿到明文
            String refundStatus = notification.getRefundStatus().toString();
            switch (refundStatus.toString()) {
                case "SUCCESS": // 支付成功
                    wechatRefund(notification);
                    break;

                case "CLOSED": // 订单关闭
                    break;

                case "PAYERROR": // 支付错误
                    break;

                default:
                    log.error("未知的退款状态: {}", refundStatus);
            }
            // 4. 返回成功响应（微信要求必须返回 SUCCESS，否则会反复重试）
            response.put("code", "SUCCESS");
            response.put("message", "处理成功");
        } catch (Exception e) {
            e.printStackTrace();
            response.put("code", "FAIL");
            response.put("message", "处理失败: " + e.getMessage());
        }
        return response;
    }

    /**
     * 处理支付成功
     */
    private void wechatPaymentSuccess(Transaction transaction) {
        // {"amount":{"currency":"CNY","payer_currency":"CNY","payer_total":2,"total":2},"appid":"wxd027385a1c298325","attach":"","bank_type":"OTHERS","mchid":"1613441716","out_trade_no":"ORD20250826235845202","payer":{"openid":"oz6WjvsibD--FLtKMMDzWfN-1xqI"},"success_time":"2025-08-27T00:15:50+08:00","trade_state":"SUCCESS","trade_state_desc":"支付成功","trade_type":"JSAPI","transaction_id":"4200002831202508275028175492"}
        String orderNo = transaction.getOutTradeNo();
        Integer payMethod = transaction.getAppid().equals(SmartParkingCloudConfig.APPID)?1:2;
        BigDecimal payAmount = new BigDecimal(transaction.getAmount().getTotal()).divide(new BigDecimal(100),2, RoundingMode.HALF_UP);
        // 停车缴费订单
        if(orderNo.indexOf("ORD") > -1){
            ParkingOrder parkingOrder = new ParkingOrder();
            parkingOrder.setOrderNo(orderNo);
            ParkingOrder order = parkingOrderMapper.selectParkingOrder(parkingOrder);
            Optional.ofNullable(order).orElseThrow(() -> new RuntimeException("暂未查询到缴费的订单"));
            order.setTransNo(transaction.getTransactionId());
            order.setUniqueId(transaction.getPayer().getOpenid());
            order.setOrderStatus(3);
            order.setPayMethod(payMethod);
            order.setPayAmount(payAmount);
            order.setPayTime(DateUtils.strToLocalDateTimeUTC(transaction.getSuccessTime()));
            order.setUpdateTime(new Date());
            parkingOrderMapper.updateParkingOrder(order);
            // 缴费成功状态通知设备
            chargeNotice(order);
        }
        // 停车卡办理订单
        if(orderNo.indexOf("CRD") > -1){
            ParkingCardOrder cardOrder = parkingCardOrderMapper.selectParkingCardOrderByOrderNo(orderNo);
            Optional.ofNullable(cardOrder).orElseThrow(() -> new RuntimeException("暂未查询到停车卡的订单"));
            cardOrder.setTransNo(transaction.getTransactionId());
            cardOrder.setUniqueId(transaction.getPayer().getOpenid());
            cardOrder.setOrderStatus(2);
            cardOrder.setPayMethod(payMethod);
            cardOrder.setPayAmount(payAmount);
            cardOrder.setPayTime(DateUtils.strToLocalDateTimeUTC(transaction.getSuccessTime()));
            cardOrder.setUpdateTime(new Date());
            parkingCardOrderMapper.updateParkingCardOrder(cardOrder);
            // 停车卡办理成功下发设备
            incrementNotice(cardOrder);
        }
    }

    /**
     * 处理退款
     */
    private void wechatRefund(RefundNotification notification) {
        // {"refund_id":"50303805432025111202459623643","out_refund_no":"CRF20251112150000445","transaction_id":"4200002852202511128677886078","out_trade_no":"CRD20251112145516638","user_received_account":"工商银行借记卡4849","success_time":"2025-11-12T15:00:09+08:00","promotion_detail":[],"amount":{"total":2,"refund":1,"payer_total":2,"payer_refund":1},"refund_status":"SUCCESS"}
        String orderNo = notification.getOutTradeNo();
        String refundTransNo = notification.getTransactionId();
        BigDecimal refundAmount = new BigDecimal(notification.getAmount().getRefund()).divide(new BigDecimal(100),2, RoundingMode.HALF_UP);
        // 停车缴费订单退款
        if(orderNo.indexOf("ORD") > -1){
        }
        // 停车卡订单退款
        if(orderNo.indexOf("CRD") > -1){
            // 查询退款单
            ParkingCardRefund parkingCardRefund = parkingCardRefundMapper.selectParkingCardRefundByRefundNo(notification.getOutRefundNo());
            Optional.ofNullable(parkingCardRefund).orElseThrow(() -> new RuntimeException("暂未查询到停车卡的退款订单"));
            parkingCardRefund.setRefundTransNo(refundTransNo);
            parkingCardRefund.setRefundAmount(refundAmount);
            parkingCardRefund.setRefundPayTime(LocalDateTime.now());
            parkingCardRefund.setRefundStatus(5);
            parkingCardRefund.setUpdateTime(new Date());
            parkingCardRefundMapper.updateParkingCardRefund(parkingCardRefund);
            // 查询订单
            ParkingCardOrder cardOrder = parkingCardOrderMapper.selectParkingCardOrderByOrderNo(orderNo);
            Optional.ofNullable(cardOrder).orElseThrow(() -> new RuntimeException("暂未查询到停车卡的订单"));

            List<ParkingCardRefund> refundList = parkingCardRefundMapper.selectParkingCardRefundByOrderNo(orderNo, 5);
            BigDecimal alreadyRefundAmount = new BigDecimal(refundList.stream().mapToDouble(e->e.getRefundAmount().doubleValue()).sum()).setScale(2, RoundingMode.HALF_UP);

            Integer refundStatus = 6; // 部分退款是6，全额退款是5
            if(refundAmount.compareTo(cardOrder.getPayAmount()) == 0 || alreadyRefundAmount.compareTo(cardOrder.getPayAmount()) == 0){ // 全部退款
                refundStatus = 5;
                // 逻辑删除停车卡，通知下级平台停车卡过期
                ParkingCard parkingCard = parkingCardMapper.selectParkingCardByOrderId(cardOrder.getId());
                if (Objects.nonNull(parkingCard)){
                    Boolean result = parkingCardRefundNotice(parkingCard, cardOrder);
                    if (result){
                        parkingCardMapper.deleteParkingCardById(parkingCard.getId());
                    }
                }
            }
            cardOrder.setOrderStatus(refundStatus);
            parkingCardOrderMapper.updateParkingCardOrder(cardOrder);
        }
    }

    /**
     * 处理订单关闭
     */
    private void wechatOrderClosed(Transaction transaction) {
        log.info("微信订单关闭: 订单号={}", transaction.getOutTradeNo());
    }

    /**
     * 处理支付错误
     */
    private void wechatPaymentError(Transaction transaction) {
        log.error("微信支付错误: 订单号={}", transaction.getOutTradeNo());
    }

    /**
     * 缴费成功状态通知
     */
    private void chargeNotice(ParkingOrder order){
        String platformId = order.getPlatformId();
        // 组装请求参数
        ChargeNoticeRequest chargeNoticeRequest = new ChargeNoticeRequest();
        chargeNoticeRequest.setPlatformId(platformId);
        chargeNoticeRequest.setCarNum(order.getCarNum());
        chargeNoticeRequest.setCarNumColor(String.valueOf(order.getCarNumColor()));
        chargeNoticeRequest.setConsumeMoney(order.getTotalAmount());
        chargeNoticeRequest.setConsumeTimeStr(DateUtils.localDateTimeToStr(order.getPayTime()));
        chargeNoticeRequest.setFavorableAmount(order.getDiscountAmount());
        chargeNoticeRequest.setFeeAmount(order.getActualAmount());
        Integer payTypeSub = 0;
        int payMethod = order.getPayMethod().intValue();
        if(payMethod == 1){
            payTypeSub = DaHuaConfig.PAY_TYPE_WECHAT_H5;
        }else if(payMethod == 2){
            payTypeSub = DaHuaConfig.PAY_TYPE_WECHAT_XCX;
        }
        chargeNoticeRequest.setPayTypeSub(payTypeSub);
        chargeNoticeRequest.setOrderStatus(DaHuaConfig.PAY_SUCCESS);
        chargeNoticeRequest.setParkingLotCode(order.getParkCode());
        chargeNoticeRequest.setSerialNumber(order.getOrderNo());

        RequestData<ChargeNoticeRequest> requestData = new RequestData<>(
                MasWebsocketEnum.CHARGE_NOTIFY.getMethod(), chargeNoticeRequest);
        CommonRequest<ChargeNoticeRequest> noticeRequest = new CommonRequest<>("transform", 1, requestData);
        log.info("缴费成功通知请求JSON：{}", chargeNoticeRequest);
        try {
            Boolean result = webSocketMessageService.operationDevice(platformId, noticeRequest);
            log.info("缴费成功通知: {}", result);
        }catch (Exception e){
            e.printStackTrace();
            log.error("缴费通知失败：{}，下级平台：{}", e.getMessage(), platformId);
        }
    }

    /**
     * 停车卡下发
     * @param cardOrder
     * @return
     */
    public void incrementNotice(ParkingCardOrder cardOrder){
        log.info("停车卡下发订单：{}", cardOrder);
        ParkingInfo parkingInfo = parkingInfoMapper.selectParkingInfoById(cardOrder.getParkId());
        String platformId = parkingInfo.getPlatformId();
        ParkingCard parkingCard = AppMapper.INSTANCE.toParkingCard(cardOrder);
        parkingCard.setValidEndTime(DateUtils.addMonths(cardOrder.getValidStartTime(), cardOrder.getValid()));
        parkingCardMapper.insertParkingCard(parkingCard);
        // 组装请求参数
        MemberCardRequest memberCardRequest = MemberCardRequest.builder()
                .cloudRecordId(String.valueOf(parkingCard.getId()))
                .carNum(cardOrder.getCarNum())
                .carNumColor(cardOrder.getCarNumColor())
                .money(cardOrder.getPayAmount())
                .owner(cardOrder.getOwner())
                .ownerTel(cardOrder.getOwnerTel())
                .parkingLotCodes(parkingInfo.getParkCode())
                .operateType(DaHuaConfig.MEMBER_CARD_ADD)
                .validStartTimeStr(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, parkingCard.getValidStartTime()))
                .validEndTimeStr(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, parkingCard.getValidEndTime()))
                .operateTimeStr(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, parkingCard.getUpdateTime()))
                .build();
        List<MemberCardRequest> list = new ArrayList<>();
        list.add(memberCardRequest);

        MemberCardListRequest memberCardList = new MemberCardListRequest();
        memberCardList.setPlatformId(platformId);
        memberCardList.setData(list);

        // 发送请求
        RequestData<MemberCardListRequest> requestData = new RequestData<>(
                MasWebsocketEnum.MEMBER_SYNC_INCREMENT.getMethod(), memberCardList);
        CommonRequest<MemberCardListRequest> cardRequest = new CommonRequest<>("transform", 1, requestData);
        log.info("停车卡下发请求JSON：{}", memberCardRequest);
        try {
            Boolean result = webSocketMessageService.operationDevice(platformId, cardRequest);
            if (result){
                cardOrder.setOrderStatus(3);
                parkingCardOrderMapper.updateParkingCardOrder(cardOrder);
            }
            log.info("停车卡下发通知: {}", result);
        } catch (Exception ex) {
            log.error("停车卡下发失败：{}，下级平台：{}", ex.getMessage(), platformId);
        }
    }

    /**
     *  停车卡订单退款，下发终端设备
     */
    public Boolean parkingCardRefundNotice(ParkingCard parkingCard, ParkingCardOrder cardOrder){
        log.info("停车卡退款下发订单：{}", cardOrder);
        ParkingInfo parkingInfo = parkingInfoMapper.selectParkingInfoById(cardOrder.getParkId());
        String platformId = parkingInfo.getPlatformId();
        String date = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, new Date());
        // 组装请求参数
        MemberCardRequest memberCardRequest = MemberCardRequest.builder()
                .cloudRecordId(String.valueOf(parkingCard.getId()))
                .carNum(cardOrder.getCarNum())
                .carNumColor(cardOrder.getCarNumColor())
                .money(cardOrder.getPayAmount())
                .owner(cardOrder.getOwner())
                .ownerTel(cardOrder.getOwnerTel())
                .parkingLotCodes(parkingInfo.getParkCode())
                .operateType(DaHuaConfig.MEMBER_CARD_UPDATE)
                .validStartTimeStr(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, parkingCard.getValidStartTime()))
                .validEndTimeStr(date)
                .operateTimeStr(date)
                .build();
        List<MemberCardRequest> list = new ArrayList<>();
        list.add(memberCardRequest);

        MemberCardListRequest memberCardList = new MemberCardListRequest();
        memberCardList.setPlatformId(platformId);
        memberCardList.setData(list);

        // 发送请求
        RequestData<MemberCardListRequest> requestData = new RequestData<>(
                MasWebsocketEnum.MEMBER_SYNC_INCREMENT.getMethod(), memberCardList);
        CommonRequest<MemberCardListRequest> cardRequest = new CommonRequest<>("transform", 1, requestData);
        log.info("停车卡退款下发请求JSON：{}", memberCardRequest);
        try {
            return webSocketMessageService.operationDevice(platformId, cardRequest);
        } catch (Exception ex) {
            log.error("停车卡退款下发失败：{}，下级平台：{}", ex.getMessage(), platformId);
        }
        return Boolean.FALSE;
    }

}
